package com.zxd.interview.weakref;

import org.junit.Test;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;


/**
 * 弱引用案例
 */
public class WeakReferenceTest {


    private static final int _1M = 1024 * 1024;

    @Test
    public void testWeakReference(){
        WeakReference<String> sr = new WeakReference<String>(new String("hello"));

        System.out.println(sr.get());
        ReferenceQueue<Object> objectReferenceQueue = new ReferenceQueue<>();
        Reference<?> poll = objectReferenceQueue.poll();
        System.gc();                //通知JVM的gc进行垃圾回收
        System.out.println(poll);
        System.out.println(sr.get());

    }

    @Test
    public void referenceAndReferenceQueue(){
        String s = "s";
        ReferenceQueue<String> reaped = new ReferenceQueue<String>();
        WeakReference<String> ws = new WeakReference<>(s, reaped);
//        s = null;
        System.gc();
        Reference<? extends String> poll1 = reaped.poll();
        System.out.println(poll1);
    }

    @Test
    public void referenceQueueUse() throws InterruptedException {
        Object value = new Object();
        Map<Object, Object> map = new HashMap<>();
        ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
        for(int i = 0;i < 10000;i++) {
            byte[] bytes = new byte[_1M];
            WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes, referenceQueue);
            map.put(weakReference, value);
        }
        // 使用主线程观察 referenceQueue 的对象回收比较麻烦
        Thread thread = new Thread(() -> {
            try {
                int cnt = 0;
                WeakReference<byte[]> k;
                // 等待垃圾回收
                while((k = (WeakReference) referenceQueue.remove()) != null) {
                    System.out.println((cnt++) + " 被回收了:" + k);
                }
            } catch(InterruptedException e) {
                //结束循环
            }
        });
//        thread.setDaemon(true);
        thread.start();
        thread.join();
    }/**
     0 被回收了:java.lang.ref.WeakReference@138caeca
     1 被回收了:java.lang.ref.WeakReference@3402b4c9
     2 被回收了:java.lang.ref.WeakReference@75769ab0
     3 被回收了:java.lang.ref.WeakReference@2e23c180
     4 被回收了:java.lang.ref.WeakReference@4aaae508
     5 被回收了:java.lang.ref.WeakReference@3e84111a
     6 被回收了:java.lang.ref.WeakReference@2cc04358
     7 被回收了:java.lang.ref.WeakReference@45bb2aa1
     8 被回收了:java.lang.ref.WeakReference@1639f93a
     9 被回收了:java.lang.ref.WeakReference@f3021cb
     */

    @Test
    public void weakHashMap(){
        WeakHashMap<String, String> map = new WeakHashMap<>();
        // 下面的注释说明 value 对于 WeakHashMap 过期没有任何影响，不管它是否在常量池当中有强引用。
        String value = new String("value");
//        String value = "value";

        // new String 此时编译器无法感知，编译阶段无法提前感知，没有强引用保留。
//        map.put(new String("key"), value); // {key=value}、

        // 对于可在编译阶段确定的字符串，系统的字符串常量池会直接记录它，自动保留对它的强引用
        map.put("key", value); // {key=value}
        System.out.println(map);

        System.gc();
        System.runFinalization();

        System.out.println(map);
    }/**运行结果：
     如果使用 new String("key") 则为下面的结果
     {key=value}
     {}

     由于直接使用了字符串字面量“key”，造成了系统对“key”字符串的缓存，对其施加了强引用，因此GC未能销毁此实例
     {key=value}
     {key=value}
     */

    /**
     * 模拟 Intern 方法
     * @param <T>
     */
    class SimulaIntern<T> {
        private WeakHashMap<T, T> weakHashMap = new WeakHashMap<T, T>();

        /**
         * 修复之后的对象使用
         */
        private WeakHashMap<String, MyObject> weakHashMapFix = new WeakHashMap<>();

        /**
         * 此方法存在问题
         * @description 此方法存在问题
         * @param item
         * @return T
         * @author xander
         * @date 2023/6/16 14:48
         */
        public T intern(T item){
            if(weakHashMap.get(item) != null){
                return weakHashMap.get(item);
            }
            // 根源在于这里的 put， 对于 key 来说是弱引用，但是 value 依旧是强引用保留
            weakHashMap.put(item, item);
            return item;
        }

        public MyObject intern(String key, MyObject value) {
            MyObject object = weakHashMapFix.get(key);
            if (object != null) {
                return object;
            }
            weakHashMapFix.put(key, value);
            return value;
        }

        public void print(){
            System.out.println("weakHashMap => "+ weakHashMap);
            System.out.println("weakHashMapFix => "+weakHashMapFix);
        }

    }

    class MyObject{

    }

    @Test
    public void testWeakMap(){
        // intern 存在问题
        SimulaIntern<String> testPool = new SimulaIntern<>();
        testPool.intern(new String("testPool"));
        testPool.print();
        System.gc();
        System.runFinalization();
        testPool.print();

        // 可以正常清理，实际上就是把 k 和 value 两者进行拆分
        SimulaIntern simulaIntern = new SimulaIntern();
        simulaIntern.intern(new String("name"), new MyObject());
        simulaIntern.print();
        System.gc();
        System.runFinalization();
        simulaIntern.print();
    }/**运行结果：
     // 无法正常清理
     weakHashMap => {testPool=testPool}
     weakHashMap => {testPool=testPool}

     // 修改之后， 可以正常清理，实际上就是把 k 和 value 两者进行拆分
     weakHashMapFix => {name=com.zxd.interview.weakref.WeakReferenceTest$MyObject@1936f0f5}
     weakHashMapFix => {}
    */


}
